package com.clp.protocol.iec104.client.pipeline;

import com.clp.protocol.iec104.client.InMaster;
import com.clp.protocol.iec104.client.config.MasterControlConfig;
import com.clp.protocol.iec104.client.config.MasterDataConfig;
import com.clp.protocol.iec104.client.pipeline.codec.MApduToBytesEncoder;
import com.clp.protocol.iec104.client.pipeline.codec.MBytesToApduDecoder;
import com.clp.protocol.iec104.client.pipeline.codec.MCompleteApduDecoder;
import com.clp.protocol.iec104.client.pipeline.state.*;
import com.clp.protocol.iec104.client.pipeline.state.control.MApduLogControlStateHandler;
import com.clp.protocol.iec104.client.pipeline.state.control.MDtInitControlStateHandler;
import com.clp.protocol.iec104.client.pipeline.state.control.MControlInfo;
import com.clp.protocol.iec104.client.pipeline.state.control.MT0T1T2T3ControlStateHandler;
import com.clp.protocol.iec104.client.pipeline.state.data.*;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelPipeline;
import lombok.Getter;

import java.util.List;

public class MPipelineManager implements MControlInfo, MDataInfo {
    @Getter
    private final InMaster inMaster;
    private final ChannelPipeline pipeline;

    private final MCompleteApduDecoder mCompleteApduDecoder;
    private final MBytesToApduDecoder mBytesToApduDecoder;
    private final MApduToBytesEncoder mApduToBytesEncoder;

    private final MApduLogControlStateHandler mApduLogControlStateHandler;
    @Getter
    private final MT0T1T2T3ControlStateHandler mt0T1T2T3ControlStateHandler;
    @Getter
    private final MDtInitControlStateHandler mDtInitControlStateHandler;

    private final MGateStateHandler mGateStateHandler;

    @Getter
    private final MTotalCall100DataHandler mTotalCall100DataHandler;
    @Getter
    private final MTotalCall101DataHandler mTotalCall101DataHandler;
    @Getter
    private final MTcDataHandler mTcDataHandler;
    @Getter
    private final MTaDataHandler mTaDataHandler;

    private final MIAsduCallbackHandler miAsduCallbackHandler;
    private final MFinalStateHandler mFinalStateHandler;

    @Getter
    private final MInternalUApduSender uApduSender;
    @Getter
    private final MInternalSApduSender sApduSender;
    @Getter
    private final MInternalIAsduSender iAsduSender;

    public MPipelineManager(InMaster inMaster, ChannelPipeline pipeline) {
        this.inMaster = inMaster;
        this.pipeline = pipeline;

        MasterControlConfig controlConfig = inMaster.getControlConfig();
        MasterDataConfig dataConfig = inMaster.getDataConfig();

        // 编解码处理器
        // 解码器，解决粘包半包问题
        this.mCompleteApduDecoder = addLast(new MCompleteApduDecoder(this));
        // 解码器，将协议内容转换成入站消息对象
        this.mBytesToApduDecoder = addLast(new MBytesToApduDecoder(this));
        // 编码器，将出站消息对象转换成协议内容
        this.mApduToBytesEncoder = addLast(new MApduToBytesEncoder(this));

        // 解码后、编码前的控制处理器链
        this.mApduLogControlStateHandler = addLast(new MApduLogControlStateHandler(this, controlConfig)); // apdu IO 日志
        this.mt0T1T2T3ControlStateHandler = addLast(new MT0T1T2T3ControlStateHandler(this, controlConfig)); // 链路keepAlive
        this.mDtInitControlStateHandler = addLast(new MDtInitControlStateHandler(this, controlConfig)); // 控制和设置启动传输标志

        // 中间处理器，用于将apdu拆装为asdu
        this.mGateStateHandler = addLast(new MGateStateHandler(this, controlConfig)); //

        // 解码后、编码前的数据处理器链
        this.mTotalCall100DataHandler = addLast(new MTotalCall100DataHandler(this, dataConfig)); // 总召唤100 - 遥测、遥信
        this.mTotalCall101DataHandler = addLast(new MTotalCall101DataHandler(this, dataConfig)); // 总召唤101 - 遥脉
        this.mTcDataHandler = addLast(new MTcDataHandler(this));
        this.mTaDataHandler = addLast(new MTaDataHandler(this));

        // 尾端
        this.miAsduCallbackHandler = addLast(new MIAsduCallbackHandler(this));
        this.mFinalStateHandler = addLast(new MFinalStateHandler(this));

        // 发送器
        this.uApduSender = new MInternalUApduSender(this);
        this.sApduSender = new MInternalSApduSender(this);
        this.iAsduSender = new MInternalIAsduSender(this, mGateStateHandler);
    }

    private <H extends ChannelHandler> H addLast(H handler) {
        pipeline.addLast(handler);
        return handler;
    }

    @Override
    public boolean isInitCompleted() {
        return mDtInitControlStateHandler.isRecvInitCompleted();
    }

    @Override
    public boolean isTestingFr() {
        return mt0T1T2T3ControlStateHandler.isTestingFr();
    }

    @Override
    public boolean isStartedDt() {
        return mDtInitControlStateHandler.isStartedDt();
    }

    @Override
    public int k() {
        return mGateStateHandler.getK();
    }

    @Override
    public int w() {
        return mGateStateHandler.getW();
    }

    @Override
    public int t0() {
        return mt0T1T2T3ControlStateHandler.getT0();
    }

    @Override
    public int t1() {
        return mt0T1T2T3ControlStateHandler.getT1();
    }

    @Override
    public int t2() {
        return mt0T1T2T3ControlStateHandler.getT2();
    }

    @Override
    public int t3() {
        return mt0T1T2T3ControlStateHandler.getT3();
    }

    @Override
    public int sendSeq() {
        return mGateStateHandler.getSendSeq();
    }

    @Override
    public int recvSeq() {
        return mGateStateHandler.getRecvSeq();
    }

    @Override
    public boolean isDoingTotalCall100() {
        return mTotalCall100DataHandler.isDoingTotalCall100();
    }

    @Override
    public boolean isDoingTotalCall101() {
        return mTotalCall101DataHandler.isDoingTotalCall101();
    }

    @Override
    public boolean isDoingTcSelect(int infoObjAddr) {
        return mTcDataHandler.isDoingOnePointTcSelect(infoObjAddr)
                || mTcDataHandler.isDoingTwoPointTcSelect(infoObjAddr);
    }

    @Override
    public boolean isDoingTcExecute(int infoObjAddr) {
        return mTcDataHandler.isDoingOnePointTcExecute(infoObjAddr)
                || mTcDataHandler.isDoingTwoPointTcExecute(infoObjAddr);
    }

    @Override
    public boolean isDoingTaSelect(int infoObjAddr) {
        return mTaDataHandler.isDoingTaSelectNormalized(infoObjAddr)
                || mTaDataHandler.isDoingTaSelectFloat(infoObjAddr)
                || mTaDataHandler.isDoingTaSelectScaled(infoObjAddr);
    }

    @Override
    public boolean isDoingTaExecute(int infoObjAddr) {
        return mTaDataHandler.isDoingTaExecuteNormalized(infoObjAddr)
                || mTaDataHandler.isDoingTaExecuteFloat(infoObjAddr)
                || mTaDataHandler.isDoingTaExecuteScaled(infoObjAddr);
    }

    @Override
    public boolean isAutoStartDtV() {
        return mDtInitControlStateHandler.isAutoStartDtV();
    }

    @Override
    public List<MTcDataHandler.PtState> listAllDoingTcPtStates() {
        return mTcDataHandler.listAllDoingTcPtStates();
    }

    @Override
    public List<MTaDataHandler.PtState> listAllDoingTaPtStates() {
        return mTaDataHandler.listAllDoingTaPtStates();
    }

    @Override
    public int totalCall100PeriodSeconds() {
        return mTotalCall100DataHandler.getPeriodSeconds();
    }

    @Override
    public int totalCall101PeriodSeconds() {
        return mTotalCall101DataHandler.getPeriodSeconds();
    }
}
